import * as THREE from 'three';
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js'
import {CSS3DRenderer} from "three/examples/jsm/renderers/CSS3DRenderer"

export default class ThreeJs{

    constructor(id){
        //根据传入的id，去获取他的dom节点，用来加载三维模型
        this.id=id;
        this.dom=document.getElementById(id);
    }

    initThree(){
        //这个初始化的是场景
        this.scene= new THREE.Scene();
        this.width=this.dom.offsetWidth;
        this.height=this.dom.offsetHeight;
        this.camera= new THREE.PerspectiveCamera(45,this.width/this.height,1,1000);

        this.camera.position.set(300,300,300);
        this.camera.lookAt(0,0,0);

        //追加webGL的渲染器，他是用来调用浏览器的GPU，去进行实时渲染（前提浏览器已经支持GPU）
        //antialias:是否开启锯齿，alpha：是否开启透明，logarithmicDepthBuffer：是否开启对数深度缓存
        this.renderer=new THREE.WebGLRenderer({antialias:true,alpha:true,logarithmicDepthBuffer:true})
        // 设置渲染器的像素比
        this.renderer.setPixelRatio(window.devicePixelRatio);
        //渲染器的输出颜色
        this.renderer.outputEncoding=THREE.sRGBEncoding;
        //设置渲染器的大小
        this.renderer.setSize(this.width,this.height);
        //将渲染器的dom元素，添加至我们div的dom元素中
        this.dom.append(this.renderer.domElement);

        // 地面网格; size:地面网格的总大小; divisions:单个网格宽度; color1:x和z方向上线的颜色; color2:其他网格线的颜色;
        const grid = new THREE.GridHelper(400, 20, 0xcccccc, 0xcccccc);
        grid.position.y = -120;
        this.scene.add(grid);

        // 立方体显示位置坐标偏移量
        const boxPositions = [
            // [0,0,0],
            [60,0,0],
            [-60,0,0],
            [0,60,0],
            [0,-60,0],
            [0,0,60],
            [0,0,-60],
            [60,60,0],
            [60,-60,0],
            [-60,60,0],
            [-60,-60,0],
            [0,60,60],
            [0,60,-60],
            [0,-60,60],
            [0,-60,-60],
            [60,0,60],
            [60,0,-60],
            [-60,0,60],
            [-60,0,-60],
            [60,60,60],
            [-60,60,60],
            [-60,-60,60],
            [60,-60,60],
            [60,60,-60],
            [-60,60,-60],
            [-60,-60,-60],
            [60,-60,-60]
        ]

        // 绘制立方体
        const material = new THREE.MeshBasicMaterial({
            color: 0xffffff,
            transparent: true,
            opacity: 1
        });

        for (let i = 0; i < boxPositions.length; i++) {
            const geometry = new THREE.BoxGeometry(40, 40, 40);
            const cube = new THREE.Mesh(geometry, material);
            const boxPosition = boxPositions[i];
            cube.position.set(boxPosition[0],boxPosition[1],boxPosition[2],);
            this.scene.add(cube);

            const edges = new THREE.EdgesGeometry(geometry);
            const lineMaterial = new THREE.LineBasicMaterial({ color: 0x000000 });
            const wireframe = new THREE.LineSegments(edges, lineMaterial);
            wireframe.position.set(boxPosition[0],boxPosition[1],boxPosition[2],);
            this.scene.add(wireframe);
        }

        // 鼠标点击事件
        // 创建射线投射器
        const raycaster = new THREE.Raycaster();
        // 鼠标位置
        const mouse = new THREE.Vector2();
        const camera1 = this.camera;
        const scence1 = this.scene;
        // 鼠标点击事件监听
        function mouseClick(event) {
            // 将鼠标坐标归一化
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
            // 设置射线起点为鼠标位置，射线的方向为相机视角方向
            raycaster.setFromCamera(mouse, camera1)
            // 计算射线相交
            const intersects = raycaster.intersectObjects(scence1.children, true)
            if (intersects.length > 0) {
                // 选中物体
                const selectedObject = intersects[0].object
                console.log(selectedObject);
            }
        }

        function mouseOver(event) {
            // 将鼠标坐标归一化
            mouse.x = (event.clientX / window.innerWidth) * 2 - 1
            mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
            // 设置射线起点为鼠标位置，射线的方向为相机视角方向
            raycaster.setFromCamera(mouse, camera1)
            // 计算射线相交
            const intersects = raycaster.intersectObjects(scence1.children, true)
            if (intersects.length > 0) {
                // 选中物体
                const selectedObject = intersects[0].object
                console.log(selectedObject);
            }
        }

        window.addEventListener('click', mouseClick, false);
        window.addEventListener('mousemove', mouseOver, false);


        // 监听浏览器大小，去更新相机的矩阵
        window.addEventListener('resize',()=>{
            // 更新相机的宽高比
            this.camera.aspect=this.dom.offsetWidth/this.dom.offsetHeight;
            this.camera.updateProjectionMatrix();
            //更新渲染器的大小
            this.renderer.setSize(this.dom.offsetWidth,this.dom.offsetHeight);
            if(this.cssRenderer){
                this.cssRenderer.setSize(this.dom.offsetWidth,this.dom.offsetHeight);
            }
        })
    }


    initHelper(helperSize=1000){
        this.scene.add(new THREE.AxesHelper(helperSize));
    }

    render(callback){
        callback();
        requestAnimationFrame(()=>this.render(callback));
    }

    initController(enableZoom=true,autoRotate=false,enableDamping=false,dampingFactor=0,minDistance=1,maxDistance=1000,minAzimuthAngle=0){
        let width=this.dom.offsetWidth;
        let height=this.dom.offsetHeight;
        //这个Renderer是用来运行3维指标，相当于一个html页面去嵌入至模型中。
        this.labelRenderer=new CSS3DRenderer();
        this.labelRenderer.setSize(width,height);
        //用来调整html页面的样式，让他围绕模型点位时，不会有偏移。
        this.labelRenderer.domElement.style.position='absolute';
        this.labelRenderer.domElement.style.top=0;
        this.labelRenderer.domElement.style.pointerEvents="none";
        this.dom.appendChild(this.labelRenderer.domElement);


        this.controller=new OrbitControls(this.camera,this.renderer.domElement);
        //设置控制器是否可以缩放
        this.controller.enableZoom=enableZoom;
        //设置是否可以旋转
        this.controller.autoRotate=autoRotate;
        //设置控制器阻尼效果，让控制器有真实的效果，
        this.controller.enableDamping=enableDamping;
        //设置阻尼控制器的系数
        this.controller.dampingFactor=dampingFactor;
        //设置控制器放大的最小距离
        this.controller.minDistance=minDistance;
        //设置控制器缩小的最大距离
        this.controller.maxDistance=maxDistance;
        //设置控制器最小旋转角度
        this.controller.minAzimuthAngle=minAzimuthAngle;
    }



}
